package com.tianqu.tms.core.util;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;

import javax.imageio.ImageIO;

import org.summercool.image.AnimatedGifEncoder;
import org.summercool.image.GifDecoder;
import org.summercool.image.Scalr;
import org.summercool.image.Scalr.Method;
import org.summercool.image.Scalr.Mode;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.tianqu.tms.core.base.Logger;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder; 


public class ImageUtils {
	public static Font FONT = new Font("微软雅黑", Font.BOLD, 18);  
	public static final Color COLOR = Color.WHITE;  
	public static final Color FONT_COLOR = new Color(255, 255, 255, 150);  
	public static final Color FONT_SHADOW_COLOR = new Color(170, 170, 170, 77);  
    
	protected static  Logger LOGGER = Logger.getLogger(ImageUtils.class);
	/**
	 * 图片转化成字符串
	 * 
	 * @param args
	 * @throws IOException
	 */
	public static String transPicToStr(String imagePath) {// 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
		try {
			File f = new File(imagePath);
			InputStream in = null;
			byte[] data = null;
			in = new FileInputStream(f);
			data = new byte[in.available()];
			in.read(data);
			in.close();
			// 对字节数组Base64编码
			BASE64Encoder encoder = new BASE64Encoder();
			return encoder.encode(data);// 返回Base64编码过的字节数组字符串
		} catch (Exception e) {
			LOGGER.error("transPicToStr error.",e);
		}
		return "";
	
	}
	
	/**
	 * 将字符串转为图片
	 * 
	 * @param imgStr
	 * @return
	 */
	public static boolean generateImageBase64(String imgStr, String imagePath) {// 对字节数组字符串进行Base64解码并生成图片
		try {
			if (imgStr == null) return false;
			BASE64Decoder decoder = new BASE64Decoder();
			// Base64解码
			byte[] b = decoder.decodeBuffer(imgStr);
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0)  b[i] += 256;
			}
			// 生成jpeg图片
			String imgFilePath = imagePath;// 新生成的图片
			OutputStream out = new FileOutputStream(imgFilePath);
			out.write(b);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			LOGGER.error("generateImage error.",e);
			return false;
		}
	}

	/**
	 * 将字符串转为图片
	 * 
	 * @param imgStr
	 * @return
	 */
	public static boolean generateImage(String imgStr, String imagePath) {// 对字节数组字符串进行Base64解码并生成图片
		try {
			if (imgStr == null) return false;
			imgStr = URLDecoder.decode(imgStr,"UTF-8");
			imgStr = imgStr.replaceAll("data:image/jpeg;base64,", "");
			BASE64Decoder decoder = new BASE64Decoder();
			// Base64解码
			byte[] b = decoder.decodeBuffer(imgStr);
			for (int i = 0; i < b.length; ++i) {
				if (b[i] < 0)  b[i] += 256;
			}
			// 生成jpeg图片
			String imgFilePath = imagePath;// 新生成的图片
			OutputStream out = new FileOutputStream(imgFilePath);
			out.write(b);
			out.flush();
			out.close();
			return true;
		} catch (Exception e) {
			LOGGER.error("generateImage error.",e);
			return false;
		}
	}
 
    public static boolean isJpg(String str) {  
        return isEndWid(str, "jpg");  
    }  
  
    public static boolean isPng(String str) {  
        return isEndWid(str, "png");  
    }  
  
    public static boolean isGif(String str) {  
        return isEndWid(str, "gif");  
    }  
  
    private static boolean isEndWid(String str, String ext) {  
        if (str == null || "".equals(str.trim())) {  
            return false;  
        }  
  
        int position = str.lastIndexOf(".");  
        if (position == -1 || (position == str.length() - 1)) {  
            return false;  
        }  
        String suffix = str.substring(position + 1);  
        if (ext.equalsIgnoreCase(suffix)) {  
            return true;  
        } else {  
            return false;  
        }  
    }  
  
    public static boolean isJpg(InputStream in) throws IOException {  
        InputStream iis = in;  
  
        if (!in.markSupported()) {  
            throw new IllegalArgumentException("Input stream must support mark");  
        }  
  
        iis.mark(30);  
        // If the first two bytes are a JPEG SOI marker, it's probably  
        // a JPEG file. If they aren't, it definitely isn't a JPEG file.  
        try {  
            int byte1 = iis.read();  
            int byte2 = iis.read();  
            if ((byte1 == 0xFF) && (byte2 == 0xD8)) {  
                return true;  
            }  
        } finally {  
            iis.reset();  
        }  
  
        return false;  
    }  
  
    public static boolean isPng(InputStream in) throws IOException {  
        if (!in.markSupported()) {  
            throw new IllegalArgumentException("Input stream must support mark");  
        }  
  
        byte[] b = new byte[8];  
        try {  
            in.mark(30);  
            in.read(b);  
        } finally {  
            in.reset();  
        }  
  
        return (b[0] == (byte) 137 && b[1] == (byte) 80 && b[2] == (byte) 78 && b[3] == (byte) 71 && b[4] == (byte) 13  
                && b[5] == (byte) 10 && b[6] == (byte) 26 && b[7] == (byte) 10);  
    }  
  
    public static boolean isGif(InputStream in) throws IOException {  
        if (!in.markSupported()) {  
            throw new IllegalArgumentException("Input stream must support mark");  
        }  
  
        byte[] b = new byte[6];  
  
        try {  
            in.mark(30);  
            in.read(b);  
        } finally {  
            in.reset();  
        }  
  
        return b[0] == 'G' && b[1] == 'I' && b[2] == 'F' && b[3] == '8' && (b[4] == '7' || b[4] == '9') && b[5] == 'a';  
    }  
  
    /**  
     * 压缩图片  
     *   
     * @param in  
     * @param out  
     * @param maxWidth  
     * @param maxHeight  
     * @param type  
     *            1: jpg 2: png 4: gif 3: jpg+png 5: jpg+gif 6: png+gif 7:  
     *            jpg+png+gif  
     * @throws IOException  
     */  
    public static void resize(InputStream in, OutputStream out, int maxWidth, int maxHeight, int type, float quality,  
            String[] watermark, Font font, Color fontColor) throws IOException {  
        if (!(type >= 1 && type <= 7)) {  
            throw new IOException("can not support type: " + type + ", type must be in [1-7] ");  
        }  
        if (type == 1) {  
            if (!isJpg(in)) {  
                throw new IOException("image format is not jpg ");  
            }  
            resizeJpg(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
            return;  
        } else if (type == 2) {  
            if (!isPng(in)) {  
                throw new IOException("image format is not png ");  
            }  
            resizePng(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
            return;  
        } else if (type == 3) {  
            if (isJpg(in)) {  
                resizeJpg(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            } else if (isPng(in)) {  
                resizePng(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            }  
            throw new IOException("image format is not jpg or png ");  
        } else if (type == 4) {  
            if (!isGif(in)) {  
                throw new IOException("image format is not gif ");  
            }  
            resizeGif(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
            return;  
        } else if (type == 5) {  
            if (isJpg(in)) {  
                resizeJpg(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            } else if (isGif(in)) {  
                resizeGif(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            }  
            throw new IOException("image format is not jpg or gif ");  
        } else if (type == 6) {  
            if (isPng(in)) {  
                resizePng(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            } else if (isGif(in)) {  
                resizeGif(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            }  
            throw new IOException("image format is not png or gif ");  
        } else if (type == 7) {  
            if (isJpg(in)) {  
                resizeJpg(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            } else if (isPng(in)) {  
                resizePng(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            } else if (isGif(in)) {  
                resizeGif(in, out, maxWidth, maxHeight, quality, watermark, font, fontColor);  
                return;  
            }  
            throw new IOException("image format is not jpg or png or gif ");  
        }  
  
    }  
  
    public static void resizeJpg(InputStream in, OutputStream out, int maxWidth, int maxHeight, float quality,  
            String[] watermark, Font font, Color fontColor) throws IOException {  
        checkParams(in, out, maxWidth, maxHeight, quality);  
        //  
        BufferedImage image = ImageIO.read(in);  
        image = Scalr.resize(image, Method.AUTOMATIC, Mode.AUTOMATIC, maxWidth, maxHeight);  
        // create new image with right size/format  
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);  
        Graphics2D g = bufferedImage.createGraphics();  
        // 因为有的图片背景是透明色，所以用白色填充 FIXED  
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1));  
        g.fillRect(0, 0, image.getWidth(), image.getHeight());  
        g.drawImage(image, 0, 0, null);  
        image = bufferedImage;  
        //  
        if (watermark != null && watermark.length > 0) {  
            makeWatermark(watermark, image, font, fontColor);  
        }  
        //  
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);  
        JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(image);  
        param.setQuality(quality, false);  
        encoder.setJPEGEncodeParam(param);  
        encoder.encode(image);  
    }  
  
    public static void resizePng(InputStream in, OutputStream out, int maxWidth, int maxHeight, float quality,  
            String[] watermark, Font font, Color fontColor) throws IOException {  
        checkParams(in, out, maxWidth, maxHeight, quality);  
        //  
        BufferedImage image = ImageIO.read(in);  
        image = Scalr.resize(image, Method.AUTOMATIC, Mode.AUTOMATIC, maxWidth, maxHeight);  
        if (watermark != null && watermark.length > 0) {  
            makeWatermark(watermark, image, font, fontColor);  
        }  
        ImageIO.write(image, "png", out);  
    }  
  
    public static void resizeGif(InputStream in, OutputStream out, int maxWidth, int maxHeight, float quality,  
            String[] watermark, Font font, Color fontColor) throws IOException {  
        checkParams(in, out, maxWidth, maxHeight, quality);  
        //  
        GifDecoder gd = new GifDecoder();  
        int status = gd.read(in);  
        if (status != GifDecoder.STATUS_OK) {  
            return;  
        }  
        //  
        AnimatedGifEncoder ge = new AnimatedGifEncoder();  
        ge.start(out);  
        ge.setRepeat(0);  
  
        for (int i = 0; i < gd.getFrameCount(); i++) {  
            BufferedImage frame = gd.getFrame(i);  
            BufferedImage rescaled = Scalr.resize(frame, Method.AUTOMATIC, Mode.AUTOMATIC, maxWidth, maxHeight);  
            if (watermark != null && watermark.length > 0) {  
                makeWatermark(watermark, rescaled, font, fontColor);  
            }  
            //  
            int delay = gd.getDelay(i);  
            ge.setDelay(delay);  
            ge.addFrame(rescaled);  
        }  
  
        ge.finish();  
    }  
  
    private static void makeWatermark(String[] text, BufferedImage image, Font font, Color fontColor) {  
        Graphics2D graphics = image.createGraphics();  
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
        if (font != null) {  
            graphics.setFont(font);  
        } else {  
            graphics.setFont(FONT);  
        }  
        if (fontColor == null) {  
            fontColor = COLOR;  
        }  
        //  
        graphics.setColor(fontColor);  
        for (int i = 0; i < text.length; i++) {  
            if ("".equals(text[i].trim())) {  
                continue;  
            }  
            FontRenderContext context = graphics.getFontRenderContext();  
            Rectangle2D fontRectangle = font.getStringBounds(text[i], context);  
            int sw = (int) fontRectangle.getWidth();  
            int sh = (int) fontRectangle.getHeight();  
            if (text.length - i == 1) {  
                graphics.drawString(text[i], image.getWidth() - sw - 6, image.getHeight() - 8);  
            } else {  
                graphics.drawString(text[i], image.getWidth() - sw - 6, image.getHeight() - sh * (text.length - 1) - 8);  
            }  
        }  
        graphics.dispose();  
    }  
  
    private static void checkParams(InputStream in, OutputStream out, int maxWidth, int maxHeight, float quality)  
            throws IOException {  
        if (in == null) {  
            throw new IOException("InputStream can not be null ");  
        }  
        if (out == null) {  
            throw new IOException("OutputStream can not be null ");  
        }  
        if (maxWidth < 1 || maxHeight < 1) {  
            throw new IOException("maxWidth or maxHeight can not be less than 1 ");  
        }  
        if (quality < 0f || quality > 1f) {  
            throw new IOException("quality must be in [0-1] ");  
        }  
    }  
    
    /**
   	 * 解析HTTP响应报文内容，并下载文件
   	 * 
   	 * @param httpUrl
   	 *            HTTP请求地址
   	 * @param saveFile
   	 *            保存到本地的地址（包含文件名）
   	 * @return
   	 */
   	public static boolean httpDownload(String httpUrl, String saveFile) {
//   		logger.info("HTTP GET请求URL:" + httpUrl);
   		//saveFile="d:/";
   		LOGGER.info("httpUrl=" + httpUrl);
   		LOGGER.info("saveFile=" + saveFile);
   		// 下载网络文件
   		int byteread = 0;

   		HttpURLConnection conn = null;
   		InputStream inStream = null;
   		FileOutputStream fileStream = null;

   		URL url = null;
   		try {
   			File file = new File(saveFile.substring(0, saveFile.lastIndexOf("/")));
   			if (!file.exists() && !file.isDirectory()) {
   				file.mkdirs();
   			}
   			
   			url = new URL(httpUrl);
   			conn = (HttpURLConnection) url.openConnection();
   			inStream = conn.getInputStream();
   			fileStream = new FileOutputStream(saveFile);

   			byte[] buffer = new byte[1204];
   			while ((byteread = inStream.read(buffer)) != -1) {
   				fileStream.write(buffer, 0, byteread);
   			}
   			return true;
   		} catch (FileNotFoundException e) {
//   			logger.warn("HTTP POST请求下载的媒体不存在！" + e);
   			return false;
   		} catch (Exception e) {
//   			logger.error("HTTP POST请求下载媒体异常！" + e);
   			return false;
   		} finally {
   			if (conn != null) {
   				conn.disconnect();
   			}

   			try {
   				if (inStream != null) {
   					inStream.close();
   				}
   				if (fileStream != null) {
   					fileStream.close();
   				}
   			} catch (IOException e) {
//   				logger.error("HTTP POST请求下载媒体资源关闭异常！" + e);
   			}
   		}
   	}

   	
   	public static String getImageDirectoryPath(String modulePath){
		String path = Registry.getConfig(TmsConstants.TMS_WEB_BASE_IMAGE_PATH)+DateUtil.getCurrentYear()+modulePath;
		File file  = new File(path);
	    if (!file.exists()) file.mkdirs();
		return path;
	}
   	
   	public static String getImageUrl(String modulePath){
		return "/image/"+DateUtil.getCurrentYear()+modulePath;
	}
    
    public static void main(String[] args) throws IOException {  
        FileInputStream in = new FileInputStream(new File("D:\\dev-tools\\eclipse\\workspace\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\tmsweb\\image\\carImageTmp\\1474905751786.jpg"));  
        FileOutputStream out = new FileOutputStream(new File("D:\\dev-tools\\eclipse\\workspace\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp0\\wtpwebapps\\tmsweb\\image\\carImageTmp\\tet.jpg"));  
        try {  
            resizeJpg(in, out, 640, 640, 0.85f, new String[] {"xwei"}, FONT, FONT_COLOR);  
        } catch (Exception e) {  
            e.printStackTrace();  
        } finally {  
            out.close();  
            in.close();  
        }  
    } 
}
